// See https://aka.ms/new-console-template for more information
using Sensor.SerialPorts;
using Sensor.SerialPorts.Enums;
using System.Text;

/// <summary>
/// 串口测试程序，用于验证串口通信功能
/// </summary>
/// <remarks>
/// 此程序创建一个串口管理器实例，打开串口连接，
/// 循环发送数据并处理接收到的数据和错误事件
/// </remarks>
class Program
{
    /// <summary>
    /// 程序入口点
    /// </summary>
    /// <param name="args">命令行参数</param>
    /// <returns>表示异步操作的任务</returns>
    static async Task Main(string[] args)
    {
        Console.WriteLine("按Enter键开始串口测试...");
        Console.ReadLine();
        
        SerialPortManager serialPortManager = new();

        // 订阅数据接收事件
        serialPortManager.BinaryFrameReceived += (data) =>
        {
            try
            {
                string receivedData = Encoding.UTF8.GetString(data);
                Console.WriteLine($"接收到数据: {receivedData.Trim()}");
            }
            catch (Exception ex)
            {
                Console.WriteLine($"处理接收数据时发生错误: {ex.Message}");
            }
        };

        // 订阅错误事件
        serialPortManager.ErrorOccurred += (error) =>
        {
            Console.WriteLine($"错误: {error}");
        };

        try
        {
            serialPortManager.Open("COM7", 115200, ParityBit.None, StopBit.One, 8);
            
            Console.WriteLine("串口已打开，开始发送数据...");
            
            // 使用CancellationToken支持取消操作
            using var cts = new CancellationTokenSource();
            
            // 处理Ctrl+C取消操作
            Console.CancelKeyPress += (sender, e) =>
            {
                e.Cancel = true;
                cts.Cancel();
                Console.WriteLine("正在取消操作...");
            };
            
            try
            {
                while (!cts.Token.IsCancellationRequested)
                {
                    // 生成单帧数据
                    string frameData = GenerateFrameData();

                    // 发送单帧数据
                    bool sendResult = serialPortManager.Send(Encoding.UTF8.GetBytes(frameData));
                    
                    if (sendResult)
                    {
                        Console.WriteLine($"发送成功: {frameData.Trim()}");
                    }
                    else
                    {
                        Console.WriteLine($"发送失败: {frameData.Trim()}");
                    }

                    await Task.Delay(100, cts.Token); // 增加延迟，确保数据有足够时间被处理
                }
            }
            catch (OperationCanceledException)
            {
                Console.WriteLine("操作已取消");
            }
        }
        catch (Exception ex)
        {
            Console.WriteLine($"错误：{ex.Message}");
        }
        finally
        {
            // 释放资源
            try
            {
                serialPortManager?.Close();
                serialPortManager?.Dispose();
            }
            catch (Exception ex)
            {
                Console.WriteLine($"释放资源时发生错误: {ex.Message}");
            }
            
            Console.WriteLine($"{DateTime.Now:yyyy-MM-dd HH:mm:ss.fff}");
            Console.WriteLine("程序已退出");
        }
    }

    /// <summary>
    /// 生成单帧数据（格式：d0 x0 y0 z0 d1 x1 y1 z1 d2 x2 y2 z2 d3 x3 y3 z3 \r\n）
    /// </summary>
    /// <returns>生成的数据帧字符串</returns>
    /// <remarks>
    /// X/Y坐标范围：-10到10
    /// Z坐标范围：0到25
    /// 所有数值保留两位小数
    /// </remarks>
    static string GenerateFrameData()
    {
        var random = new Random();

        // 生成X/Y坐标：范围-10到10
        double x0 = Math.Round(random.NextDouble() * 20 - 10, 2);
        double y0 = Math.Round(random.NextDouble() * 20 - 10, 2);
        double z0 = Math.Round(random.NextDouble() * 25, 2); // Z坐标：范围0到25

        double x1 = Math.Round(random.NextDouble() * 20 - 10, 2);
        double y1 = Math.Round(random.NextDouble() * 20 - 10, 2);
        double z1 = Math.Round(random.NextDouble() * 25, 2);

        double x2 = Math.Round(random.NextDouble() * 20 - 10, 2);
        double y2 = Math.Round(random.NextDouble() * 20 - 10, 2);
        double z2 = Math.Round(random.NextDouble() * 25, 2);

        double x3 = Math.Round(random.NextDouble() * 20 - 10, 2);
        double y3 = Math.Round(random.NextDouble() * 20 - 10, 2);
        double z3 = Math.Round(random.NextDouble() * 25, 2);

        return $"d0 {x0} {y0} {z0} " +
               $"d1 {x1} {y1} {z1} " +
               $"d2 {x2} {y2} {z2} " +
               $"d3 {x3} {y3} {z3}\r\n";
    }
}
